<?

class deploy_task extends system_task
{
	protected $instructions_map = array(
		'shell (.+)' => 'shell',
		'mongo (.+?) on (.+?)\((.+?)\)' => 'mongo',
		'task (.+)' => 'task'
	);

	protected $pre_plan = array(
		'task deploy_sources',
		'task db_migrate',
	);

	public function execute( array $params = array() )
	{
		$this->is_local = in_array('local', $params);

		$this->env = ( !in_array('stage', $params) ) ? 'prod' : 'stage';
		$production_config = file_get_contents(PROJECT_PATH . '/config/nginx/' . ( $this->is_local ? 'dev' : $this->env ) . '.conf');
		preg_match_all('/#([a-z]+)=(.+)/', $production_config, $m);

		foreach ( $m[1] as $i => $k ) $this->options[$k] = $m[2][$i];
		$this->options['root'] = PROJECT_PATH;
		$this->options['phlight_root'] = PHLIGHT_PATH;

		if ( !$this->is_local ) $this->ssh_connect();

		if ( !in_array('short', $params) ) $deployment_plan = $this->pre_plan;

		$deployed_file = PROJECT_PATH . '/data/deploy/done';
		$deployed = @file_get_contents( $deployed_file );
		$deployed = explode("\n", $deployed);

		$custom_plans = glob( PROJECT_PATH . '/data/deploy/*.release' );
		foreach ( $custom_plans as $plan_file )
		{
			$release = basename($plan_file);

			$text = file_get_contents($plan_file);
			if (in_array($release, $deployed) ) continue;
			
			$plan = explode("\n", $text);
			foreach ( $plan as $instruction ) $deployment_plan[] = $instruction;

			file_put_contents($deployed_file, $release . "\n", FILE_APPEND);
		}

		if ( $deployment_plan )
			foreach ( $deployment_plan as $instruction ) $this->process($instruction);

		if ( $this->is_local )
		{
			$task = new fix_permissions_task( $this->output );
			$task->execute( $params );
		}
	}

	public function ssh_connect()
	{
		$production_config = file_get_contents(PROJECT_PATH . '/config/nginx/' . $this->env . '.conf');
		preg_match_all('/#([a-z]+)=(.+)/', $production_config, $m);

		foreach ( $m[1] as $i => $k ) $this->options[$k] = $m[2][$i];

		$deploy_config = config::get('deploy');
		$this->out("Connecting to SSH server on {$this->options['host']}");
		$this->connection = ssh2_connect($this->options['host'], 22);

		if ( !ssh2_auth_password($this->connection, $deploy_config['user'], $deploy_config['password']) )
			return $this->error('SSH authorization failed');
	}

	public function process( $instruction )
	{
		$this->out('Instruction: ' . $instruction);

		foreach ( $this->instructions_map as $regex => $type )
		{
			$handle = 'do_' . $type;
			if ( preg_match("/{$regex}/", $instruction, $m) ) $this->$handle( $m );
		}
	}

	protected function remote_execute( $cmd )
	{
		if ( $this->is_local )
		{
			exec($cmd, $o, $r);
			return implode("\n", $o) . "\n";
		}

		$stream = ssh2_exec($this->connection, $cmd);

		stream_set_blocking( $stream, true );
		while ( !feof($stream) ) $res .= fread($stream, 8);
		fclose($stream);

		return $res;
	}

	protected function do_shell( $params )
	{
		$cmd = $params[1];
		foreach ( $this->options as $k => $v ) $cmd = str_replace("{\${$k}}", $v, $cmd);

		$this->out(" - shell executing: $cmd");
		$return = $this->remote_execute($cmd);
		echo $return;
	}

	protected function do_task( $params )
	{
		$cmd = "{$this->options['root']}/run " . $params[1];
		foreach ( $this->options as $k => $v ) $cmd = str_replace("{\${$k}}", $v, $cmd);

		$this->out(" - Task executing: $cmd");
		$return = $this->remote_execute($cmd);
		echo $return;
	}

	protected function do_mongo( $params )
	{
		$db = explode('.', $params[2]);

		switch ( $params[1] )
		{
			case 'add index':
				$cmd = "{$this->options['root']}/run mongo_eval {$db[0]}.{$db[1]} index {$params[3]}";
		}

		if ( $cmd )
		{
			$cmd = escapeshellcmd($cmd);
			$this->out(' - executing: ' . $cmd);
			$this->remote_execute($cmd);
		}
		else
		{
			$this->out('Unknown action: ' . $m[1]);
		}
	}
}